<template>
  <div class="upload-container">
    <!-- 默认触发区域 slot -->
    <div v-if="$slots.trigger" class="upload-trigger" @click="handleTriggerClick">
      <input ref="fileInput" type="file" multiple @change="handleFileChange" :disabled="uploading" class="file-input" />
      <slot name="trigger"></slot>
    </div>
    <div v-else class="default-trigger" @click="handleTriggerClick">
      <input ref="fileInput" type="file" multiple @change="handleFileChange" :disabled="uploading" class="file-input" />
      <button class="upload-button">
        <slot name="icon">
          <span class="default-icon">+</span>
        </slot>
        <slot name="text">
          <span class="default-text">选择文件</span>
        </slot>
      </button>
    </div>

    <!-- 文件列表 slot -->
    <div v-if="files.length > 0" class="upload-file-list">
      <slot name="fileList" :files="files" :removeFile="removeFile">
        <div v-for="(fileInfo, index) in files" :key="index" class="file-item">
          <div class="file-info">
            <span class="file-name">{{ fileInfo.file.name }}</span>
            <span class="file-size">{{ (fileInfo.file.size / 1024 / 1024).toFixed(2) }} MB</span>
            <span v-if="fileInfo.progress < 100" class="file-progress">{{ Math.round(fileInfo.progress) }}%</span>
            <span v-else class="file-complete">✓</span>
            <button class="remove-button" @click.stop="removeFile(index)">×</button>
          </div>
          <div v-if="fileInfo.progress > 0" class="file-progress-bar">
            <div class="progress" :style="{ width: `${fileInfo.progress}%` }"></div>
          </div>
        </div>
      </slot>
    </div>

    <!-- 操作按钮 slot -->
    <div class="upload-actions">
      <slot name="actions" :uploadFiles="uploadFiles" :files="files" :uploading="uploading">
        <button @click="uploadFiles" :disabled="files.length === 0 || uploading" class="upload-action-button">
          {{ uploading ? '上传中...' : '开始上传' }}
        </button>
      </slot>
    </div>

    <!-- 进度条 slot -->
    <div v-if="uploading" class="upload-progress">
      <slot name="progress" :progress="totalProgress">
        <div class="progress-container">
          <div class="progress-bar" :style="{ width: `${totalProgress}%` }"></div>
          <span>{{ Math.round(totalProgress) }}%</span>
        </div>
      </slot>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed } from 'vue'
import { createFileChunk, calculateHash } from '../../utils/fileChunk'

const fileInput = ref<HTMLInputElement | null>(null)
const files = ref<Array<{
  file: File
  progress: number
  hash?: string
  chunks?: Array<any>
}>>([])
const uploading = ref(false)
const chunkSize = ref(5 * 1024 * 1024) // 5MB 每个分片大小

const totalProgress = computed(() => {
  if (files.value.length === 0) return 0
  const total = files.value.reduce((sum, fileInfo) => sum + fileInfo.progress, 0)
  return total / files.value.length
})

const handleTriggerClick = () => {
  if (fileInput.value && !uploading.value) {
    fileInput.value.value = '' // 清除之前的选择，允许重复选择同一文件
    fileInput.value.click()
  }
}

const handleFileChange = (e: Event) => {
  const target = e.target as HTMLInputElement
  if (target.files && target.files.length > 0) {
    // 添加新文件到列表，过滤掉重复文件
    const newFiles = Array.from(target.files).filter(file =>
      !files.value.some(f => f.file.name === file.name && f.file.size === file.size)
    )

    files.value = [
      ...files.value,
      ...newFiles.map(file => ({
        file,
        progress: 0,
        hash: undefined,
        chunks: undefined
      }))
    ]
  }
}

const removeFile = (index: number) => {
  if (!uploading.value) {
    files.value.splice(index, 1)
  }
}

const uploadFiles = async () => {
  if (files.value.length === 0) return

  uploading.value = true
  // 重置所有文件进度
  files.value = files.value.map(fileInfo => ({
    ...fileInfo,
    progress: 0
  }))

  try {
    // 为每个文件计算hash并创建分片
    await Promise.all(files.value.map(async (fileInfo) => {
      fileInfo.hash = await calculateHash(fileInfo.file)
      fileInfo.chunks = createFileChunk(fileInfo.file, chunkSize.value)
    }))

    // 上传所有文件的分片
    await Promise.all(
      files.value
        .filter(fileInfo => fileInfo.hash !== undefined && fileInfo.chunks !== undefined)
        .map(fileInfo =>
          uploadFile(fileInfo as {
            file: File
            progress: number
            hash: string
            chunks: Array<any>
          })
        )
    )

    // 上传成功回调
    if (props.onSuccess) {
      props.onSuccess(files.value.map(f => f.file))
    }
  } catch (error) {
    console.error('上传失败:', error)
    // 上传失败回调
    if (props.onError) {
      props.onError(error)
    }
  } finally {
    uploading.value = false
  }
}

const uploadFile = async (fileInfo: {
  file: File
  progress: number
  hash: string
  chunks: Array<any>
}) => {
  if (!fileInfo.hash || !fileInfo.chunks) {
    throw new Error('File info is incomplete')
  }
  const { hash, chunks } = fileInfo

  // 上传每个分片
  const requests = chunks.map((chunk, index) => {
    const formData = new FormData()
    formData.append('file', chunk.file)
    formData.append('hash', `${hash}-${index}`)
    formData.append('filename', fileInfo.file.name)
    formData.append('fileHash', hash)
    formData.append('chunkIndex', index.toString())
    formData.append('chunkCount', chunks.length.toString())

    return uploadChunk(formData, (e: ProgressEvent) => {
      // 更新单个分片的上传进度
      const loaded = e.loaded
      const total = e.total
      const chunkProgress = (loaded / total) * 100
      // 更新文件进度
      fileInfo.progress = ((index / chunks.length) * 100) + (chunkProgress / chunks.length)
    })
  })

  await Promise.all(requests)

  // 通知服务器合并分片
  await mergeChunks(hash, fileInfo.file.name, chunks.length)

  // 标记文件为100%完成
  fileInfo.progress = 100
}

const uploadChunk = async (formData: FormData, onProgress: (e: ProgressEvent) => void) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    xhr.open('POST', '/api/uploader', true)

    xhr.upload.onprogress = onProgress

    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(xhr.response)
      } else {
        reject(xhr.statusText)
      }
    }

    xhr.onerror = () => reject('上传出错')

    xhr.send(formData)
  })
}

const mergeChunks = async (fileHash: string, filename: string, chunkCount: number) => {
  const response = await fetch('/api/uploader', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      action: 'merge',
      fileHash,
      filename,
      chunkCount,
    }),
  })

  if (!response.ok) {
    throw new Error('合并分片失败')
  }

  return response.json()
}

// 定义组件props
const props = defineProps({
  onSuccess: {
    type: Function,
    default: null
  },
  onError: {
    type: Function,
    default: null
  },
  // customizeTrigger: {
  //   type: Boolean,
  //   default: false
  // }
})
</script>

<style scoped>
.upload-container {
  max-width: 600px;
  margin: 0 auto;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}

.file-input {
  display: none;
}

.default-trigger {
  display: inline-block;
  cursor: pointer;
}

.upload-button {
  padding: 10px 16px;
  background-color: #409eff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s;
}

.upload-button:hover {
  background-color: #66b1ff;
}

.upload-button:disabled {
  background-color: #a0cfff;
  cursor: not-allowed;
}

.default-icon {
  margin-right: 8px;
  font-size: 16px;
}

.upload-file-list {
  margin-top: 15px;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
}

.file-item {
  margin-bottom: 10px;
  padding: 8px;
  border-radius: 4px;
  transition: background-color 0.3s;
}

.file-item:hover {
  background-color: #f5f7fa;
}

.file-info {
  display: flex;
  align-items: center;
  margin-bottom: 5px;
}

.file-name {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 14px;
  color: #606266;
}

.file-size {
  margin: 0 10px;
  color: #909399;
  font-size: 12px;
}

.file-progress,
.file-complete {
  margin: 0 10px;
  font-size: 12px;
}

.file-progress {
  color: #409eff;
  font-weight: bold;
}

.file-complete {
  color: #67c23a;
}

.remove-button {
  background: none;
  border: none;
  color: #f56c6c;
  cursor: pointer;
  font-size: 16px;
  padding: 0 5px;
}

.remove-button:hover {
  color: #f78989;
}

.file-progress-bar {
  height: 6px;
  background-color: #ebeef5;
  border-radius: 3px;
  overflow: hidden;
}

.file-progress-bar .progress {
  height: 100%;
  background-color: #409eff;
  transition: width 0.3s;
}

.upload-actions {
  margin-top: 15px;
  text-align: right;
}

.upload-action-button {
  padding: 9px 15px;
  background-color: #409eff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

.upload-action-button:hover {
  background-color: #66b1ff;
}

.upload-action-button:disabled {
  background-color: #a0cfff;
  cursor: not-allowed;
}

.progress-container {
  margin: 10px 0;
  height: 20px;
  background-color: #ebeef5;
  border-radius: 4px;
  position: relative;
}

.progress-bar {
  height: 100%;
  background-color: #409eff;
  border-radius: 4px;
  transition: width 0.3s;
}

.progress-container span {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  color: white;
  font-size: 12px;
}
</style>